package com.shao.im.webSocket;

import com.shao.im.webSocket.base.BaseChannelInHandler;
import com.shao.im.webSocket.base.BaseChannelOutHandler;
import com.shao.im.webSocket.handler.TextMessageChannelHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Optional;

@Component
@Slf4j
public class WsServer {

    @Value("${server.ws.port}")
    private int port;

    @Autowired(required = false)
    public List<BaseChannelInHandler> baseChannelInHandlers;

    private final EventLoopGroup master = new NioEventLoopGroup();
    private final EventLoopGroup slave = new NioEventLoopGroup();

    /**
     * 启动WebSocket服务
     */
    public void start() {
        ServerBootstrap serverBootstrap = new ServerBootstrap()
                .group(master, slave)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        ChannelPipeline pipeline = ch.pipeline();
                        // http编解码器
                        pipeline.addLast(new HttpServerCodec());
                        // http聚合器
                        pipeline.addLast(new HttpObjectAggregator(1024 * 1024));
                        // WebSocket协议
                        pipeline.addLast(new WebSocketServerProtocolHandler("/im"));
                        // 自定义消息的处理
                        pipeline.addLast(new TextMessageChannelHandler());
                        // 出栈消息处理器
                        pipeline.addLast(new BaseChannelOutHandler());
                        // 将开发者自定义的ChannelInHandler添加到流水线中
                        Optional.ofNullable(baseChannelInHandlers)
                                .ifPresent(baseChannelInHandlers1 -> {
                                    for (BaseChannelInHandler baseChannelInHandler : baseChannelInHandlers1) {
                                        pipeline.addLast(baseChannelInHandler);
                                    }
                                });
                    }
                });

        // 绑定端口
        ChannelFuture channelFuture = serverBootstrap.bind(port);
        channelFuture.addListener(future -> {
            if (future.isSuccess()) {
                log.info("【WebSocket start】 webSocket 服务器启动成功，端口号为：- {}", port);
            } else {
                log.info("【WebSocket start】 webSocket 服务器启动失败!", future.cause());
                // 强行关闭spring
                System.exit(1);
            }
        });
    }

    /**
     * 销毁WebSocket服务
     */
    public void destroy() {
        log.info("【webSocket stop】 webSocket 服务器停止运行！");
        // Netty的优雅关机，不会接受新的连接和请求，会处理完当前的请求
        master.shutdownGracefully();
        slave.shutdownGracefully();
    }
}
